package util

import (
	"bufio"
	"errors"
	"os"
	"path/filepath"
	"sort"
	"sync"
	"time"
)

var errCreatingFile = errors.New("error creating new file")
var errClosingFile = errors.New("error closing File")
var errRenamingFile = errors.New("error renaming File")
var errDeletingFile = errors.New("error deleting File")

const DEFAULT_ROTATE_AND_DELETE_BOOL = false
const DEFAULT_MAX_FILES = 10

type RotateWriter struct {
	lock            sync.Mutex
	filename        string // should be set to the actual filename
	duration        int
	fp              *os.File
	rotateAndDelete bool
	maxFiles        int
}

func NewWriter(filename string, maxFiles int, rotateAndDelete bool) (*RotateWriter, error) {
	// Check file before we initialize.
	return new(filename, maxFiles, rotateAndDelete)
}

func new(filename string, maxFiles int, rotateAndDelete bool) (*RotateWriter, error) {
	w := &RotateWriter{filename: filename, duration: -1, maxFiles: maxFiles, rotateAndDelete: rotateAndDelete}
	err := w.Rotate()
	if err != nil {
		return nil, err
	}
	// Trigger a rotation after every x interval.
	//ticker := time.NewTicker(time.Duration(int64(w.duration)) * time.Second)
	//go func() {
	//	for {
	//		select {
	//		case <-ticker.C:
	//			w.Rotate()
	//		}
	//	}
	//}()
	return w, nil
}

// NewWriter makes a new RotateWriter. Return nil if error occurs during setup.
//func NewWriter(filename string, timeInSec int) (*RotateWriter, error) {
//	// Check file before we initialize.
//	return new(filename, timeInSec)
//}

//func new(filename string, duration int) (*RotateWriter, error) {
//	w := &RotateWriter{filename: filename, duration: duration}
//	err := w.Rotate()
//	if err != nil {
//		return nil, err
//	}
//	// Trigger a rotation after every x interval.
//	ticker := time.NewTicker(time.Duration(int64(w.duration)) * time.Second)
//	go func() {
//		for {
//			select {
//			case <-ticker.C:
//				w.Rotate()
//			}
//		}
//	}()
//	return w, nil
//}

// Write satisfies the io.Writer interface.
func (w *RotateWriter) Write(output []byte) (int, error) {
	w.lock.Lock()
	defer w.lock.Unlock()
	return w.fp.Write(output)
}

func (w *RotateWriter) Close() (err error) {
	return w.fp.Close()
}

func (w *RotateWriter) GetFileSize() (int64, error) {
	w.lock.Lock()
	defer w.lock.Unlock()

	fi, err := w.fp.Stat()
	if err != nil {
		return 0, err
	}
	return fi.Size(), nil
}

// Perform the actual act of rotating and reopening file.
func (w *RotateWriter) Rotate() (err error) {
	w.lock.Lock()
	defer w.lock.Unlock()

	// Close existing file if open
	if w.fp != nil {
		err = w.fp.Close()
		w.fp = nil
		if err != nil {
			return errClosingFile
		}
	}
	// Rename dest file if it already exists
	_, err = os.Stat(w.filename)
	if err == nil {
		if w.rotateAndDelete {
			err = os.Remove(w.filename)
			if err != nil {
				return errDeletingFile
			}
		} else {
			err = os.Rename(w.filename, w.filename+"."+time.Now().Format(time.RFC3339))
			if err != nil {
				return errRenamingFile
			}

			//maxfiles func
			matches, _ := filepath.Glob(w.filename + ".*")
			sort.Strings(matches)
			// heng:
			// why here max files need maxFiles - 1
			// because log file will have no exten ver
			// for example if max files is 4
			// logxxx logxxx.1 logxxx.2 logxxx.3
			// all .* will have max fils -1  = 3
			// with logxxx total will be 4
			if len(matches) > w.maxFiles-1 {
				for i := 0; i < len(matches)-w.maxFiles+1; i++ {
					os.Remove(matches[i])
				}
			}
		}
	}

	// Create a file.
	w.fp, err = os.Create(w.filename)
	if err != nil {
		return errCreatingFile
	}
	return nil
}

func (w *RotateWriter) Read() ([]string, error) {
	var buffer []string

	fp, err := os.Open(w.filename)
	if err != nil {
		return nil, err
	}
	// File is already open we use the scanner on it.
	scanner := bufio.NewScanner(fp)
	for scanner.Scan() {
		text := scanner.Text()
		buffer = append(buffer, text)
	}
	if err := scanner.Err(); err != nil {
		return nil, err
	}
	return buffer, nil
}
